import LogicFlow, { EdgeConfig, NodeConfig } from '@logicflow/core';
import { lfJson2Xml } from '@logicflow/extension';
import { MutableRefObject, useCallback, useEffect, useState } from 'react';
import { ISaveType, LfFlowChartProps } from '../types';
import { defaultTheme } from './contants';

export const useFlowChart = (
  props: LfFlowChartProps,
  conf: {
    lf: MutableRefObject<LogicFlow | null>;
    lfBoxRef: MutableRefObject<HTMLDivElement | null>;
  },
) => {
  const { lf, lfBoxRef } = conf;
  const [theme, setTheme] = useState<string>(defaultTheme); // 主题
  const [openSelectMore, setOpenSelectMore] = useState(false); // 是否开启框选
  const [isUndoAble, setIsUndoAble] = useState(false); // 是否有上一步
  const [isRedoAble, setIsRedoAble] = useState(false); // 是否有下一步
  const [activeNodes, setActiveNodes] = useState<NodeConfig[]>([]); // 选中的节点
  const [activeEdges, setEdgeNodes] = useState<EdgeConfig[]>([]); // 选中的边
  const [properties, setProperties] = useState<Record<string, unknown>>({}); // 选中的元素（节点/边）的属性集合

  useEffect(() => {
    if (props.theme) {
      setFlowChartTheme();
    }
  }, [props?.theme]);

  /**
   * 设置流程图主题
   */
  const setFlowChartTheme = useCallback(() => {
    lfBoxRef.current?.style.setProperty('--themeColor', props.theme!);
    lfBoxRef.current?.style.setProperty(
      '--activeColor',
      props.styleConf?.iconActiveColor || '#8b5df6',
    );
    setTheme(props.theme!);
  }, [props.theme, lfBoxRef]);

  /**
   * 获取被选中节点的样式属性
   */
  const getSelectNodeOrEdgeStyles = () => {
    setTimeout(() => {
      const { nodes, edges } = (lf.current as LogicFlow).getSelectElements();

      // 标记那些是选中的节点/边
      setActiveNodes(nodes);
      setEdgeNodes(edges);

      // 记录选中节点/边的属性
      let _properties = {};
      if (nodes?.length) {
        nodes.forEach((node) => {
          _properties = { ...properties, ...node.properties };
        });
      }
      if (edges?.length) {
        edges.forEach((edge) => {
          _properties = { ...properties, ...edge.properties };
        });
      }
      setProperties(_properties);
    }, 50);
  };

  /**
   * 回退到上一步/下一步
   */
  const onChangeUndoOrRedo = (info: any) => {
    const {
      data: { undoAble = false, redoAble = false },
    } = info;
    setIsUndoAble(undoAble);
    setIsRedoAble(redoAble);
  };

  /**
   * 开启/关闭 框选
   */
  const selectMoreNode = () => {
    if (openSelectMore) {
      (
        lf.current as LogicFlow
      ).extension.selectionSelect.closeSelectionSelect();
    } else {
      (lf.current as LogicFlow).extension.selectionSelect.openSelectionSelect();
    }

    setOpenSelectMore(!openSelectMore);
  };

  /**
   *  回退上一步、下一步
   * @params type 用于判断是回退到上一步或下一步的操作
   */
  const lfUndoOrRedo = useCallback(
    (type: boolean) => {
      if (type && isUndoAble) {
        (lf.current as LogicFlow).undo();
      } else if (!type && isRedoAble) {
        (lf.current as LogicFlow).redo();
      }
    },
    [lf],
  );

  /**
   * 画布放大或缩小
   * @params type 用于判断画布是放大或缩小
   */
  const lfZoomInOrOut = useCallback(
    (type: boolean) => (lf.current as LogicFlow).zoom(type),
    [lf],
  );

  /**
   * 保存流程图数据（json、xml、png）
   * @params type 用于判断保存的数据类型
   */
  const saveFlowChartInfo = useCallback(
    (type: ISaveType) => {
      if (!lf.current) return;

      switch (type) {
        case 'image': {
          lf.current.getSnapshot();
          break;
        }
        case 'json': {
          const data = lf.current.getGraphData();
          console.log('JSON 数据', data);
          props.saveInfo?.(data, 'json');
          break;
        }
        case 'xml': {
          const data = lfJson2Xml(lf.current.getGraphData());
          console.log('XML 数据', data);
          props.saveInfo?.(data, 'xml');
          break;
        }
        default:
          return new Error('类型不对');
      }
    },
    [lf],
  );

  /**
   * 开启缩略图
   */
  const openMiniMap = () => {
    const x = props.styleConf?.miniMapPosition?.x || 1000;
    const y = props.styleConf?.miniMapPosition?.y || 10;
    (lf.current as LogicFlow).extension.miniMap.show(x, y);
  };

  /**
   * 添加节点
   * @params type 每个自定义节点必须且唯一的属性
   */
  const dragInNode = useCallback(
    (type: string) => {
      (lf.current as LogicFlow).dnd.startDrag({
        type,
      });
    },
    [lf],
  );

  /**
   * 修改选中节点的样式
   * @params styles 编辑的样式属性
   */
  const stylesChange = (styles: Record<string, unknown>) => {
    activeNodes.forEach(({ id }) => {
      (lf.current as LogicFlow).setProperties(id as string, styles);
    });
    activeEdges.forEach(({ id }) => {
      (lf.current as LogicFlow).setProperties(id as string, styles);
    });
    getSelectNodeOrEdgeStyles();
  };

  /**
   * 设置选中节点的层级
   * @params type 用于判断所选中节点的层级
   */
  const setZIndex = (type: 'top' | 'bottom') => {
    activeNodes.forEach(({ id }) => {
      (lf.current as LogicFlow).setElementZIndex(id as string, type);
    });
    activeNodes.forEach(({ id }) => {
      (lf.current as LogicFlow).setElementZIndex(id as string, type);
    });
  };

  return {
    lfZoomInOrOut,
    saveFlowChartInfo,
    openMiniMap,
    dragInNode,
    lfUndoOrRedo,
    selectMoreNode,
    stylesChange,
    setZIndex,
    onChangeUndoOrRedo,
    getSelectNodeOrEdgeStyles,
    properties,
    openSelectMore,
    activeEdges,
    activeNodes,
    theme,
  };
};
